package com.gradecak.alfresco.mvc.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.alfresco.model.ContentModel;
import org.alfresco.service.namespace.QName;
import org.codehaus.jackson.annotate.JsonAnySetter;
import org.codehaus.jackson.annotate.JsonIgnore;

import com.gradecak.alfresco.mvc.action.Action;

public abstract class AbstractAlfrescoObject implements ContentObject, Comparable<CMObject>, Serializable {

  private static final long serialVersionUID = 7027040916417993371L;

  protected final CMObject contentObject;

  protected final Map<String, Serializable> unknownProperties = new HashMap<String, Serializable>();

  public AbstractAlfrescoObject() {
    this(Boolean.FALSE);
  }

  public AbstractAlfrescoObject(final Boolean acceptNullProperties) {
    contentObject = new CMObject(acceptNullProperties);
    contentObject.addReadOnlyProperty(ContentModel.PROP_MODIFIER);
    contentObject.addReadOnlyProperty(ContentModel.PROP_MODIFIED);
    contentObject.addReadOnlyProperty(ContentModel.PROP_NODE_REF);
  }

  public void beforeSaveCallback() {
    // empty template method intended to be overridden if needed
  }

  public List<Action> getActions() {
    return contentObject.getActions();
  }

  public List<QName> getAspects() {
    return contentObject.getAspects();
  }

  public String getSysRef() {
    Object ref = contentObject.getProperty(ContentModel.PROP_NODE_REF);
    return ref != null ? ref.toString() : null;
  }

  public void setSysRef(final String value) {
    contentObject.setProperty(ContentModel.PROP_NODE_REF, value);
  }

  public String getModifier() {
    return (String) contentObject.getProperty(ContentModel.PROP_MODIFIER);
  }

  public void setModifier(final String value) {
    contentObject.setProperty(ContentModel.PROP_MODIFIER, value);
  }

  public String getCreator() {
    return (String) contentObject.getProperty(ContentModel.PROP_CREATOR);
  }

  public void setCreator(final String value) {
    contentObject.setProperty(ContentModel.PROP_CREATOR, value);
  }

  public Date getModified() {
    return (Date) contentObject.getProperty(ContentModel.PROP_MODIFIED);
  }

  public void setModified(final Date value) {
    contentObject.setProperty(ContentModel.PROP_MODIFIED, value);
  }

  public Date getCreated() {
    return (Date) contentObject.getProperty(ContentModel.PROP_CREATED);
  }

  public void setCreated(final Date value) {
    contentObject.setProperty(ContentModel.PROP_CREATED, value);
  }

  @JsonIgnore
  public CMObject getContentObject() {
    return contentObject;
  }

  @JsonIgnore
  public Map<String, Object> getUnkwonProperties() {
    return new HashMap<String, Object>(unknownProperties);
  }

  @JsonAnySetter
  public void handleUnknownProperty(final String key, final Object value) {
    if (key == null || value == null) {
      return;
    }

    if (!(value instanceof Serializable)) {
      throw new RuntimeException("Cannot handle a non serializable property. Key/Value: " + key + "/" + value);
    }

    unknownProperties.put(key, (Serializable) value);
  }

  public int hashCode() {
    String sysRef = getSysRef();
    return sysRef == null ? 0 : sysRef.hashCode();
  }

  public boolean equals(final Object obj) {
    String sysRef = getSysRef();
    if (obj instanceof ContentObject && sysRef != null) {
      return sysRef.equals(((ContentObject) obj).getSysRef());
    }
    return false;
  }

  public int compareTo(final CMObject obj) {
    String sysRef = getSysRef();
    if (obj instanceof ContentObject && sysRef != null) {
      return sysRef.compareTo(((ContentObject) obj).getSysRef());
    }
    return -1;
  }
}
